package com.yauthor.module
{
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	
	/**
	 * Holds component state.
	 */
	public class ComponentState implements IStateLoadContext, IStateSaveContext
	{
		/**
		* Array of saved state data.
		*/
		protected var m_stateData:ByteArray;
		
		/**
		* Array of children-modules states.
		*/
		protected var m_childrenStates:Array;
		
		/**
		* Indicates if state is valid;
		*/
		protected var m_validState:Boolean;
		
		private var childLoadCounter:Number;
		
		public function isValid():Boolean {
			return m_validState;
		}
		
		public function ComponentState() {
			m_stateData = new ByteArray();
			m_childrenStates = [];
			m_validState = false;		
		}
		
		public function saveChildrenState( childArray:Array ):void {			
			for ( var i:Number = 0; i < childArray.length; i++ ) {
				if ( childArray[i] is com.yauthor.module.IStatefull ) {
					var childState:ComponentState = new ComponentState();
					childState.prepareStateSave();
					( childArray[i] as com.yauthor.module.IStatefull ).saveState( childState );
					m_childrenStates.push(childState);
				}
			}
			m_validState = true;
		}
		
		public function saveChildState( child:com.yauthor.module.IStatefull ):void {
			var childState:ComponentState = new ComponentState();
			childState.prepareStateSave();
			child.saveState(childState);
			m_childrenStates.push(childState);
			m_validState = true;
		}
		
		public function loadChildrenState( childArray:Array ):void {
			for ( var i:Number = 0; i < childArray.length; i++ ) {
				var state:ComponentState = m_childrenStates[childLoadCounter] as ComponentState;
				if ( childArray[i] is com.yauthor.module.IStatefull ) {
					if(state != null){
						state.prepareStateLoad();
						( childArray[i] as com.yauthor.module.IStatefull ).loadState(state);
					}
					childLoadCounter++;
				}
			}
		}
		
		public function loadChildState( child:com.yauthor.module.IStatefull ):void {
			(m_childrenStates[childLoadCounter] as ComponentState).prepareStateLoad();
			child.loadState( m_childrenStates[childLoadCounter] as ComponentState );
			childLoadCounter++;
		}							
		
		/**
		 * Prepares object for load state operation.
		 * 
		 */
		public function prepareStateLoad():void {
			m_stateData.position = 0;
			childLoadCounter = 0;
		}
		
		/**
		 * Prepares object for save state operation.
		 * 
		 */
		public function prepareStateSave():void {
			m_stateData = new ByteArray();
			m_validState = true;
			
			m_childrenStates = [];
		}
		
		public function get dataInput():IDataInput {			
			return m_stateData as IDataInput;
		}
		
		public function get dataOutput():IDataOutput {		
			return m_stateData as IDataOutput;
		}
		
		public function get childrenStates():Array{
			return m_childrenStates;
		}
		
		public function consolidateData():ByteArray {
			m_stateData.position = 0;
			var cData:ByteArray = new ByteArray;
			cData.writeUnsignedInt( m_stateData.bytesAvailable );
			cData.writeBytes( m_stateData );
			
			var childCData:ByteArray;
			for each ( var childState:ComponentState in m_childrenStates ) {
				childCData = childState.consolidateData();
				cData.writeUnsignedInt( childCData.bytesAvailable );
				cData.writeBytes( childCData );
			}
			
			cData.position = 0;
			return cData;
		}
		
		public function loadConsolidatedData( cData:ByteArray ):void {
			var tSize:Number;
			
			cData.position = 0;
			tSize = cData.readUnsignedInt();
			
			if ( tSize > 0 ) {
				cData.readBytes(m_stateData, 0, tSize);
			}
			
			m_childrenStates = [];
			while ( cData.bytesAvailable != 0 ) {
				var childState:ComponentState = new ComponentState();
				var childCData:ByteArray = new ByteArray();
				
				tSize = cData.readUnsignedInt();
				cData.readBytes(childCData, 0, tSize);
				childState.loadConsolidatedData(childCData);		
				m_childrenStates.push(childState);
			}
			
			//invalid state will contain only one byte 0 - amount of state bytes.
			if ( cData.length > 1 ) {
				m_validState = true;	
			}		
		}
		
	}
}